#include "Technique.h"
Technique::Technique(void)
{
}
Technique::~Technique(void)
{
	glDeleteProgram ( mProgramObject );
}
char* Technique::textFileRead(char *fn)
{
	FILE *fp;
	char *content = NULL;

	int count=0;

	if (fn != NULL) {
		fp = fopen(fn,"rt");

		if (fp != NULL) {

			fseek(fp, 0, SEEK_END);
			count = ftell(fp);
			rewind(fp);

			if (count > 0) {
				content = (char *)malloc(sizeof(char) * (count+1));
				count = fread(content,sizeof(char),count,fp);
				content[count] = '\0';
			}
			fclose(fp);
		}
	}
	return content;
	//std::ifstream is (fn,std::ifstream::binary);
	//if (is)
	//{
	//	// get length of file:
	//	is.seekg (0, is.end);
	//	int length = is.tellg();
	//	is.seekg(0,is.beg);
	//	// allocate memory:
	//	char * buffer = new char [length+1];
	//	is.read (buffer,length);
	//	buffer[length] = '\0';
	//	is.close();
	//	return buffer;
	//}
}

bool Technique::onInit(char* vs_path,char* fs_path)
{
	char *vertShaderSrc = textFileRead(vs_path);
	char *fragShaderSrc = textFileRead(fs_path);
	GLint linked;
	// Load the vertex/fragment shaders
	mVertexShader = loadShader ( GL_VERTEX_SHADER, vertShaderSrc );
	if ( mVertexShader == 0 )
		return 0;

	mFragmentShader = loadShader ( GL_FRAGMENT_SHADER, fragShaderSrc );
	if ( mFragmentShader == 0 )
	{
		glDeleteShader( mFragmentShader );
		return 0;
	}

	// Create the program object
	mProgramObject = glCreateProgram ( );

	if ( mProgramObject == 0 )
		return 0;

	glAttachShader ( mProgramObject, mVertexShader );
	glAttachShader ( mProgramObject, mFragmentShader );

	// Link the program
	glLinkProgram ( mProgramObject );

	// Check the link status
	glGetProgramiv ( mProgramObject, GL_LINK_STATUS, &linked );

	if ( !linked ) 
	{
		GLint infoLen = 0;

		glGetProgramiv ( mProgramObject, GL_INFO_LOG_LENGTH, &infoLen );

		if ( infoLen > 1 )
		{
			char* infoLog = (char*)malloc (sizeof(char) * infoLen );

			glGetProgramInfoLog ( mProgramObject, infoLen, NULL, infoLog );
			printf( "Error linking program:\n%s\n", infoLog );            

			free ( infoLog );
		}

		glDeleteProgram ( mProgramObject );
		return 0;
	}
	load();
	// Free up no longer needed shader resources
	glDeleteShader ( mVertexShader );
	glDeleteShader ( mFragmentShader );
	return 1;
}
void Technique::load()
{
	mWVPLoc = getUniformLocation("gWVP");
	mWorldMatrixLoc = getUniformLocation("gWorld");
}
void Technique::SetWVP(const Matrix4f& WVP)
{
	glUniformMatrix4fv(mWVPLoc, 1, GL_TRUE, (const GLfloat*)WVP.m);    
}
void Technique::setWorldMatrix(const Matrix4f& WorldInverse)
{
	glUniformMatrix4fv(mWorldMatrixLoc, 1, GL_TRUE, (const GLfloat*)WorldInverse.m);
}
void Technique::setTextureUint(GLuint texureUnit)
{
	glUniform1i ( mTexureLoc, texureUnit );
}
GLuint Technique::getAttribLocation(const char* pAttrName)
{
	return glGetAttribLocation ( mProgramObject, pAttrName );
}
GLuint Technique::getUniformLocation(const char* pUniformName)
{
	return glGetUniformLocation ( mProgramObject, pUniformName );
}
void Technique::enable()
{
	 glUseProgram(mProgramObject);
}
void Technique::disable()
{
	glUseProgram(0);
}
GLuint Technique::loadShader ( GLenum type, const char *shaderSrc )
{
	GLuint shader;
	GLint compiled;

	// Create the shader object	
	shader = glCreateShader ( type );

	if ( shader == 0 )
		return 0;

	// Load the shader source
	glShaderSource ( shader, 1, &shaderSrc, NULL );

	// Compile the shader
	glCompileShader ( shader );

	// Check the compile status
	glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );

	if ( !compiled ) 
	{
		GLint infoLen = 0;

		glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );

		if ( infoLen > 1 )
		{
			char* infoLog = (char*)malloc (sizeof(char) * infoLen );

			glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
			printf ( "Error compiling shader:\n%s\n", infoLog );            

			free ( infoLog );
		}

		glDeleteShader ( shader );
		return 0;
	}
	return shader;
}